package gui;

import java.awt.*;
import java.awt.event.*;

import gameBasicElements.*;
import javax.swing.*;
import player.MovementSource;

/**
 * @author Wojciech Łopata
 *
 */

public class BoardDrawer extends JPanel
{
	private static final long serialVersionUID = 6615531622031134015L;
	
	private final JPanel grid;
	private final BoardMovementSource movementSource;
	private final JButton passButton;
	private final Color background;
	
	private Square [][] squares;
	private int boardSize;
	
	private enum SquareType
	{
		INNER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(0, square.getHeight()/2, square.getWidth(), square.getHeight()/2);
				g.drawLine(square.getWidth()/2, 0, square.getWidth()/2, square.getHeight());
			}
		},
		
		TOP_LEFT_CORNER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth(), square.getHeight()/2);
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth()/2, square.getHeight());
			}
		},
		
		TOP_RIGHT_CORNER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(square.getWidth()/2, square.getHeight()/2, 0, square.getHeight()/2);
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth()/2, square.getHeight());
			}
		},
		
		BOTTOM_LEFT_CORNER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth(), square.getHeight()/2);
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth()/2, 0);
			}
		},
		BOTTOM_RIGHT_CORNER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(square.getWidth()/2, square.getHeight()/2, 0, square.getHeight()/2);
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth()/2, 0);
			}
		},
		
		LEFT_BORDER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth(), square.getHeight()/2);
				g.drawLine(square.getWidth()/2, 0, square.getWidth()/2, square.getHeight());
			}
		},
		
		TOP_BORDER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(0, square.getHeight()/2, square.getWidth(), square.getHeight()/2);
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth()/2, square.getHeight());
			}
		},
		
		RIGHT_BORDER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(square.getWidth()/2, square.getHeight()/2, 0, square.getHeight()/2);
				g.drawLine(square.getWidth()/2, 0, square.getWidth()/2, square.getHeight());
			}
		},
		
		BOTTOM_BORDER
		{
			@Override
			public void drawLines(Graphics g, Square square)
			{
				g.drawLine(0, square.getHeight()/2, square.getWidth(), square.getHeight()/2);
				g.drawLine(square.getWidth()/2, square.getHeight()/2, square.getWidth()/2, 0);
			}
		};
		
		public abstract void drawLines(Graphics g, Square square);
	}
	
	private class BoardMovementSource implements MovementSource
	{
		private Position pos;
		private boolean locked = true;
		
		public synchronized void setPosition(Position pos)
		{
			if(!locked)
			{
				this.pos = pos;
				notifyAll();
			}
		}
		
		@Override
		public synchronized Position getMove()
		{
			locked = false;
			while(pos == null)
					try
					{
						wait();
					} catch (InterruptedException e)
					{
						return null;
					}
			try
			{
				return pos.getX() == -1 ? null : pos;
			}
			finally
			{
				locked = true;
				pos = null;
			}
		}
	};
	
	private class Square extends JButton
	{
		private static final long serialVersionUID = 5562446647267698054L;
		private final SquareType type;
		private final BoardMovementSource movementSource;
		private final Position posInLayout;
		private PlayerColor playerColor;
		
		public Square(SquareType type, BoardMovementSource boardMovementSource, Position myPositionInLayout)
		{
			super();
			this.type = type;
			this.movementSource = boardMovementSource;
			this.posInLayout = myPositionInLayout;
			
			playerColor = null;
			setBackground(background);
			setBorderPainted(false);
			
			addActionListener(new ActionListener()
			{
				@Override
				public void actionPerformed(ActionEvent e)
				{
					movementSource.setPosition(posInLayout);
				}
			});

		}
		
		public void setPlayerColor(PlayerColor color)
		{
			this.playerColor = color;
		}
		
		public PlayerColor getPlayerColor()
		{
			return playerColor;
		}
		
		@Override
		public void paint(Graphics g)
		{
			super.paint(g);
			type.drawLines(g, this);
			if(playerColor != null)
			{
				g.setColor(playerColor.equals(PlayerColor.WHITE) ? Color.white : Color.black);
				g.fillOval(0, 0, getWidth() - 2, getHeight() - 2);
			}
		}
	}
	
	private void setBoard(Board board)
	{
		grid.removeAll();
		int boardSize = board.getSize();
		grid.setLayout(new GridLayout(boardSize, boardSize));
		squares = new Square[boardSize][boardSize];
		
		squares[0][0] = new Square(SquareType.TOP_LEFT_CORNER, movementSource, new Position(0, 0));
		squares[boardSize - 1][0] = new Square(SquareType.BOTTOM_LEFT_CORNER, movementSource, new Position(boardSize - 1, 0));
		squares[0][boardSize - 1] = new Square(SquareType.TOP_RIGHT_CORNER, movementSource, new Position(0, boardSize - 1));
		squares[boardSize - 1][boardSize - 1] = new Square(SquareType.BOTTOM_RIGHT_CORNER, movementSource, new Position(boardSize - 1, boardSize - 1));
		
		for(int i = 1; i < boardSize - 1; ++i)
			squares[i][0] = new Square(SquareType.LEFT_BORDER, movementSource, new Position(i, 0));
		
		for(int i = 1; i < boardSize - 1; ++i)
			squares[i][boardSize - 1] = new Square(SquareType.RIGHT_BORDER, movementSource, new Position(i, boardSize - 1));
		
		for(int i = 1; i < boardSize - 1; ++i)
			squares[0][i] = new Square(SquareType.TOP_BORDER, movementSource, new Position(0, i));
		
		for(int i = 1; i < boardSize - 1; ++i)
			squares[boardSize - 1][i] = new Square(SquareType.BOTTOM_BORDER, movementSource, new Position(boardSize - 1, i));
		
		for(int i = 1; i < boardSize - 1; ++i)
			for(int j = 1; j < boardSize - 1; ++j)
				squares[i][j] = new Square(SquareType.INNER, movementSource, new Position(i, j));
			
		
		for(int i = 0; i < boardSize; ++i)
			for(int j = 0; j < boardSize; ++j)
				grid.add(squares[i][j]);
		grid.validate();
		repaint();
	}
	
	public BoardDrawer(Dimension dim)
	{
		grid = new JPanel();
		grid.setPreferredSize(dim);
		setLayout(new FlowLayout());
		
		background = new Color(154, 109, 50);
		setBackground(background);
		movementSource = new BoardMovementSource();
		passButton = new JButton("PAS");
		passButton.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent arg0)
			{
				movementSource.setPosition(new Position(-1, -1));
			}
		});
		
		boardSize = -1;
		add(passButton);
		add(grid);
		
	}
	
	public void update(Board b)
	{
		if(boardSize != b.getSize()) setBoard(b);
		for(int i = 0; i < b.getSize(); ++i)
			for(int j = 0; j < b.getSize(); ++j)
				if(b.getPlayerColor(new Position(i, j)) != squares[i][j].getPlayerColor()) // != instead of equals due to nulls 
				{
					squares[i][j].setPlayerColor(b.getPlayerColor(new Position(i, j)));
					squares[i][j].repaint();
				}
	}
	
	public void clean()
	{
		for(int i = 0; i < boardSize; ++i)
			for(int j = 0; j < boardSize; ++j)
			{
				squares[i][j].setPlayerColor(null);
				squares[i][j].repaint();
			}
	}
	
	public void enablePassButton(boolean b)
	{
		passButton.setEnabled(b);
		passButton.setVisible(b);
	}
	
	public MovementSource getMovementSource()
	{
		return movementSource;
	}
}